//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.imu.security;

import java.util.Date;
import java.util.Enumeration;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.springframework.util.StringUtils;

import com.imu.common.exception.ErrorDesc;
import com.imu.common.exception.RRException;
import com.imu.common.validator.Assert;
import com.imu.utils.ShortUUID;
import com.xiaoleilu.hutool.crypto.SecureUtil;

public class SessionTokenProviderMemory extends SessionTokenProviderAbstract 
{
    protected static final ConcurrentHashMap<String, SessionObject> sessions = new ConcurrentHashMap<String, SessionObject>();
    protected long expiresInMilliseconds = 0L;
    protected long sessionClenanerLaunchInMinutes = 60L;
    private static SessionTokenProviderMemory me;

    private static ISessionTokenProvider initialize() 
    {
        if(me == null) 
        {
            me = new SessionTokenProviderMemory();
        }

        return me;
    }

    public static ISessionTokenProvider getSessionTokenProvider() 
    {
        return initialize();
    }

    public static void destroySessionTokenProvider() 
    {
        me = null;
    }

    public SessionTokenProviderMemory() 
    {
        this.setTimeout(this.expiresInMilliseconds);
    }

    public void setTimeout(long timeoutInMilliseconds) 
    {
        this.expiresInMilliseconds = timeoutInMilliseconds;
    }

    public SessionObject setSession(String id, String term ,String username, String sex, boolean mobile) 
    {
    	Assert.isBlank(id,  ErrorDesc.PARAM_EMPTY.getMsg(), ErrorDesc.PARAM_EMPTY.getCode());
    	Assert.isBlank(term,  ErrorDesc.PARAM_EMPTY.getMsg(), ErrorDesc.PARAM_EMPTY.getCode());
    	Assert.isBlank(username, ErrorDesc.PARAM_EMPTY.getMsg(), ErrorDesc.PARAM_EMPTY.getCode());
    	
        String token = ShortUUID.UUID();
        long now = (new Date()).getTime();
        String secret = SecureUtil.md5(id + term);
        SessionObject info = SessionObject.create(token.toString(), id, username, sex, secret, term, now, now + this.expiresInMilliseconds);
        sessions.put(secret +":"+ token, info);
        return info;
    }

    public SessionObject updateSession(String secret, String token, SessionObject info)
    {
    	Assert.isBlank(info,  ErrorDesc.PARAM_EMPTY.getMsg(), ErrorDesc.PARAM_EMPTY.getCode());
    	Assert.isBlank(token,  ErrorDesc.PARAM_EMPTY.getMsg(), ErrorDesc.PARAM_EMPTY.getCode());
    	long now = (new Date()).getTime();
    	info.setStartTime(now);
    	info.setExpirationTime(now + this.expiresInMilliseconds);
    	sessions.put(secret +":"+ token, info);
        return info;
    }

    public SessionObject getSession(String secret, String token) 
    {
    	Assert.isBlank(token,  ErrorDesc.PARAM_EMPTY.getMsg(), ErrorDesc.PARAM_EMPTY.getCode());
    	Assert.isBlank(secret, ErrorDesc.PARAM_EMPTY.getMsg(), ErrorDesc.PARAM_EMPTY.getCode());
    	
        if(this.isExpired(secret, token))
        {
            return null;
        }
        else 
        {
            SessionObject info = (SessionObject)sessions.get(secret +":"+ token);
            if(info == null)
            {
                this.removeSession(secret, token);
                return null;
            }
            else
            {
                info.setExpirationTime((new Date()).getTime() + this.expiresInMilliseconds);
                return info;
            }
        }
    }

    public void removeSession(String secret, String token)
    {
    	Assert.isBlank(token,  ErrorDesc.PARAM_EMPTY.getMsg(), ErrorDesc.PARAM_EMPTY.getCode());
    	Assert.isBlank(secret, ErrorDesc.PARAM_EMPTY.getMsg(), ErrorDesc.PARAM_EMPTY.getCode());
    	
        sessions.remove(secret +":"+ token);
    }
    
    public void removeSession(String secret)
    {
    	Assert.isBlank(secret, ErrorDesc.PARAM_EMPTY.getMsg(), ErrorDesc.PARAM_EMPTY.getCode());
        sessions.remove(secret +":*");
    }
    
    public Enumeration<String> getTokens() 
    {
        return sessions.keys();
    }

    private boolean isExpired(String secret, String token)
    {
    	Assert.isBlank(token,  ErrorDesc.PARAM_EMPTY.getMsg(), ErrorDesc.PARAM_EMPTY.getCode());
    	Assert.isBlank(secret, ErrorDesc.PARAM_EMPTY.getMsg(), ErrorDesc.PARAM_EMPTY.getCode());
    	
        SessionObject info = (SessionObject)sessions.get(secret +":"+ token);
        if(info == null) 
        {
            return true;
        } 
        else if(this.expiresInMilliseconds != 0L && (new Date()).getTime() > Long.valueOf(info.getExpirationTime()).longValue())
        {
            this.removeSession(secret, token);
            return true;
        }
        else
        {
            return false;
        }
    }

    public List<SessionObject> getSessions(String username) 
    {
    	Assert.isBlank(username,  ErrorDesc.PARAM_EMPTY.getMsg(), ErrorDesc.PARAM_EMPTY.getCode());
    	
        Stream<SessionObject> values = sessions.values().stream().filter((x) -> 
        {
            return x.getUsername().equals(username);
        });
        
        List<SessionObject> toRet = (List<SessionObject>)values.collect(Collectors.toList());
        return toRet;
    }

    public SessionObject getCurrent(String secret, String token)
    {
    	Assert.isBlank(token,  ErrorDesc.PARAM_EMPTY.getMsg(), ErrorDesc.PARAM_EMPTY.getCode());
    	Assert.isBlank(secret, ErrorDesc.PARAM_EMPTY.getMsg(), ErrorDesc.PARAM_EMPTY.getCode());
    	
        return token != null?(SessionObject)sessions.get(secret +":"+ token):null;
    }
    
    public String getUserId(String secret, String token)
    {
    	Assert.isBlank(token,  ErrorDesc.PARAM_EMPTY.getMsg(), ErrorDesc.PARAM_EMPTY.getCode());
    	Assert.isBlank(secret, ErrorDesc.PARAM_EMPTY.getMsg(), ErrorDesc.PARAM_EMPTY.getCode());
    	
    	SessionObject session = getCurrent(secret, token);
    	if(null == session || StringUtils.isEmpty(session.getUsername()))
        {
        	throw new RRException("SESSION过期或不存在", 501);
        }
        
    	return session.getUsername();
    }
}
